package org.future.dev.encrypt;

import java.io.IOException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 加密
 * @author shixg
 * @date 2009-12-23 下午02:36:22
 */
public class EncryptUtils {
    // 算法名称 可查看 
    // http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA
    // 
    private static final String KEY_MD5 = "MD5";
    private static final String KEY_SHA = "SHA";
    private static final String KEY_HMAC = "HmacMD5";
    private static final String KEY_DES = "DES";
    
    /**
     * base64 编码 [可逆]
     * @param key :byte[]
     * @return String
     */
    public static String encryptBase64(byte[] key){
        String res = new BASE64Encoder().encodeBuffer(key);
        int len = res.length();      
        res = res.substring(0,len-2);              // 删除末尾的 \r\n
        return res;
    }
    /**
     * base64 编码 [可逆]
     * @param key :String
     * @return String
     */
    public static String encryptBase64(String key){
        return encryptBase64(key.getBytes());
    }
    /**
     * base64 解码
     * @param key :String
     * @return byte[]
     */
    public static byte[] decryptBase64(String key){
        byte[] plaintext = null;
        try {
            plaintext = new BASE64Decoder().decodeBuffer(key);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return plaintext;
    }
    /**
     * MD5 加密 [不可逆]
     * Message Digest Algorithm 5 信息摘要算法
     * @param key :byte[]
     * @return byte[] 16 位的 md5 值
     */
    public static byte[] encryptMd5(byte[] key){
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance(KEY_MD5);
            md5.update(key);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        if(md5 == null){
            return null;
        }
        return md5.digest();
    }
    /**
     * MD5 加密 [不可逆]
     * Message Digest Algorithm 5 信息摘要算法
     * @param key :String
     * @return byte[] 16 位的 md5 值
     */
    public static byte[] encryptMd5(String key){
        byte[] ciphertext = encryptMd5(key.getBytes());
        return ciphertext;
    }
    /**
     * SHA 加密[不可逆] 
     * Secure Hash Algorithm 安全散列算法
     * @param key :byte[]
     * @return byte[]
     */
    public static byte[] encryptSha(byte[] key){
        MessageDigest sha = null;
        try{
            sha = MessageDigest.getInstance(KEY_SHA);
            sha.update(key);
        } catch(NoSuchAlgorithmException e){
            e.printStackTrace();
        }
        if(sha == null){
            return null;
        }
        return sha.digest();
    }
    /**
     * SHA 加密[不可逆] 
     * Secure Hash Algorithm 安全散列算法
     * @param key :String
     * @return byte[]
     */
    public static byte[] encryptSha(String key){
        byte[] ciphertext = encryptSha(key.getBytes());
        return ciphertext;
    }
    /**
     * 初始化 HMAC 密钥
     * Hash Message Authentication Code 散列消息鉴别码
     * @return String
     */
    public static String initMackey(){
        SecretKey key = null;
        try{
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_HMAC);
            key = keyGenerator.generateKey();
        } catch(NoSuchAlgorithmException e){
            e.printStackTrace();
        }
        if(key == null){
            return null;
        }
        return new String((key.getEncoded()));
    }
    /**
     * HMAC 加密 [不可逆]
     * Hash Message Authentication Code 散列消息鉴别码
     * @param data :byte[]
     * @param key :String
     * @return byte[]
     */
    public static byte[] encryptHmac(byte[] data,String key){
        byte[] bytekey = key.getBytes();
        SecretKey secretKey = new SecretKeySpec(bytekey, KEY_HMAC);
        Mac mac = null;
        try {
            mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(mac == null){
            return null;
        }
        return mac.doFinal(data);
    }
    /**
     * 生成 DES 密钥
     * Data Encryption Standard 数据加密标准算法
     * @param seed :String
     * @return String
     */
    public static String initDesKey(String seed){
        SecureRandom secureRandom = null;
        if(seed == null){
            secureRandom = new SecureRandom();
        } else{
            byte[] byteseed = seed.getBytes();
            secureRandom = new SecureRandom(byteseed);
        }
        KeyGenerator keyg = null;
        try {
            keyg = KeyGenerator.getInstance(KEY_DES);
            keyg.init(secureRandom);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKey secretKey = keyg.generateKey();
        return new String((secretKey.getEncoded()));
    }
    /**
     * 转换 DES 密钥
     * @param key :byte[]
     * @return Key
     */
    private static Key toKey(byte[] key){
        SecretKey secretKey = null;
        try{
            if(key.length < 8){
                int len = key.length;
                byte[] tempkey = new byte[len + 8];
                System.arraycopy(key, 0, tempkey, 0, len);
                byte[] preKey = new byte[]{'1','a','2','c','5','h','\u0013','u'};
                System.arraycopy(preKey, 0, tempkey, len, 8);
                key = tempkey;
            }
            DESKeySpec dks = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_DES);
            secretKey = keyFactory.generateSecret(dks);
        } catch(Exception e){
            e.printStackTrace();
        }
        return secretKey;
    }
    /**
     * DES 加密
     * Data Encryption Standard 数据加密标准算法
     * @param data :byte[]
     * @param key :String
     * @return byte[]
     */
    public static byte[] encryptDes(byte[] data,String key){
        Key k = toKey(key.getBytes());
        Cipher cipher = null;
        byte[] res = null;
        try{
            cipher = Cipher.getInstance(KEY_DES);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            res = cipher.doFinal(data);
        } catch(Exception e){
            e.printStackTrace();
        }       
        return res;
    }
    /**
     * DES 解密
     * Data Encryption Standard 数据加密标准算法
     * @param data :byte[]
     * @param key :String
     * @return byte[]
     */
    public static byte[] decryptDes(byte[] data,String key){
        Key k = toKey(key.getBytes());
        Cipher cipher = null;
        byte[] res = null;
        try{
            cipher = Cipher.getInstance(KEY_DES);
            cipher.init(Cipher.DECRYPT_MODE, k);
            res = cipher.doFinal(data);
        } catch(Exception e){
            e.printStackTrace();
        }       
        return res;
    }
}
